using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace streaming
{
    /// <summary>
    /// 帧率模式
    /// </summary>
    public enum FramerateMode
    {
        /// <summary>
        /// 低帧率，在加载界面为这个模式
        /// </summary>
        Low,
        /// <summary>
        /// 中等帧率，如果需要边进行游戏边执行任务使用这个模式
        /// </summary>
        medium,
        /// <summary>
        /// 流畅帧率，需要逻辑任务不影响帧率使用这个模式
        /// </summary>
        High
    }


    /// <summary>
    /// 任务总线接口
    /// </summary>
    public interface IEventBus
    {

    }

    /// <summary>
    /// 流式任务类
    /// </summary>
    public class StreamingEvent
    {
        /// <summary>
        /// 逻辑任务，在Streaming中认为这个Action是最小不可分割单位
        /// </summary>
        public Action Action;
        /// <summary>
        /// 优先级，越大越优先
        /// </summary>
        public int Priority = 1;


        public StreamingEvent(Action action, int prioritty)
        {
            Action = action;
            Priority = prioritty;
        }
    }

    /// <summary>
    /// 流式任务总线
    /// 用于控制业务代码的耗时，防止业务代码卡帧率
    /// </summary>
    public static class StreamingEventBus
    {
        /// <summary>
        /// 任务列表
        /// </summary>
        private static LinkedList<StreamingEvent> _streamingEvents;

        /// <summary>
        /// 代码计时器
        /// </summary>
        private static Stopwatch sw;

        public static FramerateMode framerateMode = FramerateMode.High;

        /// <summary>
        /// 添加流式任务
        /// </summary>
        /// <param name="self"></param>
        /// <param name="action"></param>
        public static void AddEvent(this IEventBus self, Action action, int Priority = 1) 
        {
            StreamingEvent Event = new(action, Priority);
            AddEvent(Event);
        }

        /// <summary>
        /// 添加匿名流式任务
        /// </summary>
        /// <param name="action"></param>
        /// <param name="Priority"></param>
        public static void AddEvent(Action action, int Priority = 1) 
        {
            StreamingEvent Event = new(action, Priority);
            AddEvent(Event);
        }

        /// <summary>
        /// 添加流式任务的执行函数
        /// </summary>
        /// <param name="Event"></param>
        public static void AddEvent(StreamingEvent Event)
        {
            if (_streamingEvents.Count == 0) { _streamingEvents.AddLast(Event); return; }

            var Current = _streamingEvents.First;
            while (Current != null)
            {
                if (Current.Value.Priority > Event.Priority) break;
                Current = Current.Next;
            }

            if (Current == null) _streamingEvents.AddLast(Event);
            else _streamingEvents.AddBefore(Current, Event);
        }

        /// <summary>
        /// 根据帧率模式获取脚本执行时间
        /// </summary>
        /// <returns></returns>
        private static long GetScriptTime()
        {
            switch (framerateMode)
            {
                case FramerateMode.Low:
                    {
                        return 50;
                    }
                    
                case FramerateMode.medium:
                    {
                        return 10;
                    }
                    
                case FramerateMode.High:
                    {
                        return 5;
                    }
                default: return 10;
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public static void Init()
        {
            _streamingEvents = new();
            sw = new();
        }

        /// <summary>
        /// 执行托管的业务逻辑
        /// </summary>
        public static void Update()
        {
            if (_streamingEvents.Count == 0) return;
            sw.Start();
            var Current = _streamingEvents.First;
            while (Current!=null)
            {
                try
                {
                    if (Current.Value.Action != null)
                        Current.Value.Action.DynamicInvoke();
                }
                catch (Exception e)
                {
                    UnityEngine.Debug.LogError(e.Message + "\n" + e.StackTrace);
                }
                var temp = Current;
                Current = Current.Next;
                _streamingEvents.Remove(temp);
                if (sw.ElapsedMilliseconds >= GetScriptTime())
                {
                    //超时
                    sw.Stop();
                    return;
                }
            }
            _streamingEvents.Clear();
            sw.Stop();
        }

    }
}

